/*
 * resfilter.c
 *
 * 		Modified version of: http://www.musicdsp.org/showArchiveComment.php?ArchiveID=29
 *
 * 		Added envelope functionality
 *
 * 		Frequency range:
 * 		Attack section: 	min frequency to max frequency
 * 		Decay section:		max frequency to mid-point of min and max frequencies
 * 		Sustain section:	mid-point of min and max frequencies
 * 		Release section:	mid-point of min and max frequencies to min frequency
 *
 */

#include <stdint.h>
#include <defs.h>
#include <resfilter.h>

static float cut_lp;					// cut
static float fb_lp;						// feedback

static int32_t filterAttackSampleTime;	// attack sample time
static int32_t filterDecaySampleTime;	// decay sample time
static int32_t filterReleaseSampleTime;	// release sample time

static float filterAttackInc;			// attack increment value
static float filterDecayInc;			// decay increment value
static float filterReleaseInc;			// release increment value

static float filterFrequency;			// current frequency value
static int32_t filterSection;			// current envelope section
static float filterMinFrequency;		// min frequency
static int32_t counter;					// sample counter


/****************************************************************************
* DESCRIPTION: Update filter cut-off frequency
* RETURN:      none
*****************************************************************************/
void resFilter_cutoff(float cutoffFreq, float res_lp) {
	cut_lp = cutoffFreq * (2.0 / sampleRate);
	fb_lp = res_lp + res_lp / (1.0 - cut_lp);
}

/****************************************************************************
* DESCRIPTION: Process a sample through the filter
* RETURN:      int32_t new sample value
*****************************************************************************/
int32_t resFilter(int32_t sampleIn) {
	static int32_t buf0;
	static int32_t buf1;
	buf0 = buf0 + cut_lp * (sampleIn - buf0 + fb_lp * (buf0 - buf1));
	buf1 = buf1 + cut_lp * (buf0 - buf1);
	return buf1;
}

/****************************************************************************
* DESCRIPTION: Initialise the frequency modulation envelope
* RETURN:      none
*****************************************************************************/
void resFilter_freqEnvInit(float attackTime, float decayTime, float releaseTime, float filterMinFreq, float filterMaxFreq) {

	// calculate sample times for each section
	filterAttackSampleTime = attackTime * (sampleRate);
	filterDecaySampleTime = decayTime * (sampleRate);
	filterReleaseSampleTime = releaseTime * (sampleRate);

	// calculate increments for each section
	filterAttackInc  = (filterMaxFreq - filterMinFreq) / filterAttackSampleTime;
	filterDecayInc	 = ( (filterMaxFreq - filterMinFreq) / 2.0) / filterDecaySampleTime;
	filterReleaseInc = ( (filterMaxFreq - filterMinFreq) / 2.0) / filterReleaseSampleTime;

	// remember min frequency
    filterMinFrequency = filterMinFreq;

    // initial frequency value
	filterFrequency = filterMinFreq;

	// set initial section
	filterSection = ATTACK;

	// init counter
	counter = 0;
}

/****************************************************************************
* DESCRIPTION: Update the envelope
* RETURN:      float new frequency value
*****************************************************************************/
float resFilter_freqEnvUpdate() {

	// if envelope is in attack section
	if(filterSection == ATTACK){

		// add increment to current frequency value
		filterFrequency += filterAttackInc;

		// check if this section is complete
		counter++;
		if(counter == filterAttackSampleTime) {
			counter = 0;
			filterSection = DECAY;
		}
	}
	// if envelope is in decay section
	else if(filterSection == DECAY) {

		// subtract increment value from current frequency value
		filterFrequency -= filterDecayInc;

		// check if this section is complete
		counter++;
		if(counter == filterDecaySampleTime) {
			counter = 0;
			filterSection = SUSTAIN;
		}
	}
	// if envelope is in sustain section
	else if(filterSection == SUSTAIN) {
		// do nothing
	}
	// if envelope is in release section
	else if(filterSection == RELEASE) {

		// if current frequency is more than
		if( !(filterFrequency <= filterMinFrequency) ) {
			// subtract increment value from current frequency value
			filterFrequency -= filterReleaseInc;
		}
	}
	// return new frequency
	return filterFrequency;
}

/****************************************************************************
* DESCRIPTION: Set envelope section to release
* RETURN:      none
*****************************************************************************/
void resFilter_freqEnvRelease() {
	filterSection = RELEASE;
}
